package foc.physics.solver;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.text.Html;
import android.text.InputType;
import android.util.TypedValue;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;
import core.Formula;
import core.Global;
import core.Var;
import misc.Rounding;

public class GenericSolver extends Activity {

    private EditText[] textBoxes;
    /*Units index which the corresponding spinner is set to*/
    private int[] currentUnits;
    private String[] unitNames;
    /**
     * Unformatted variables such as v<sub>f</sub>
     */
    private String[] names;
    private double[][] conversionFactors;
    private String[] variables;
    private Spinner[] spinners;
    private String type;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle extras = getIntent().getExtras();
        int size = extras.getInt("size");
        names = extras.getStringArray("formattedNames");
        unitNames = extras.getStringArray("units");
        variables = extras.getStringArray("variables");
        type = extras.getString("key");
        textBoxes = new EditText[size];
        currentUnits = new int[size];
        conversionFactors = new double[size][];
        spinners = new Spinner[size];


        setContentView(R.layout.formula);


        CharSequence[] formattedNames = new CharSequence[size];
        for (int i = 0; i < size; i++)
            formattedNames[i] = Html.fromHtml(names[i]);

        TableLayout t = (TableLayout) findViewById(R.id.solver_table);


        for (int i = 0; i < size; i++) {
            CharSequence[] s = toHtml(Global.units.get(unitNames[i]));
            t.addView(createTableRow(formattedNames[i], s, i));
            conversionFactors[i] = initializeUnits(Global.conv.get(unitNames[i]));
        }

        findViewById(R.id.solve_button).setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                solve();
            }
        });

        if (savedInstanceState != null) {
            String[] text = savedInstanceState.getStringArray("textBoxes");
            currentUnits = savedInstanceState.getIntArray("currentUnits");
            for (int i = 0; i < text.length; i++) {
                textBoxes[i].setText(text[i]);
                spinners[i].setSelection(currentUnits[i]);
            }
        }
    }

    private void solve() {
        double[] userValues = new double[textBoxes.length];
        for (int i = 0; i < textBoxes.length; i++) {
            String s = textBoxes[i].getEditableText().toString();
            if (s.length() == 0) {
                userValues[i] = Double.MAX_VALUE;
                Global.values.remove(variables[i]);//Kinda inefficient ... but at least its constant time.
            } else
                userValues[i] = Double.parseDouble(s) * conversionFactors[i][currentUnits[i]];
        }
        for (int i = 0; i < textBoxes.length; i++)
            if (userValues[i] != Double.MAX_VALUE)
                Global.values.put(variables[i], new Var(variables[i], userValues[i], 6)); //TODO: introduce sigFigs
        boolean changes = true;
        while (changes) {
            changes = false;
            for (Formula f : Global.formulas.get(type)) {
                String s = f.works();
                if (s != null && !Global.values.containsKey(s)) {
                    Var x = f.evaluate(this);
                    if (x == null)
                        continue;
                    Global.values.put(x.name, x);
                    int index = findName(x.name);
                    textBoxes[index].setText(
                            Rounding.round(x.value / conversionFactors[index][currentUnits[index]], x.sigFig) + "");
                    changes = true;
                }
            }
        }

    }

    private int findName(String variable) {
        for (int i = 0; i < variables.length; i++)
            if (variables[i].equals(variable))
                return i;
        return -1;
    }

    private CharSequence[] toHtml(Integer integer) {
        String[] s = getResources().getStringArray(integer);
        CharSequence[] b = new CharSequence[s.length];
        for (int i = 0; i < s.length; i++) {
            String a = s[i].replaceAll("\\+sup", "<sup><small>");
            a = a.replaceAll("\\-sup", "</small></sup>");
            b[i] = Html.fromHtml(a);
        }
        return b;
    }

    public TableRow createTableRow(CharSequence name, CharSequence[] elements, final int count) {
        TableRow t = new TableRow(this);
        TableRow.LayoutParams params = new TableRow.LayoutParams(TableRow.LayoutParams.FILL_PARENT,
                TableRow.LayoutParams.WRAP_CONTENT);
        params.setMargins(dipToPx(4)
                , 0, 0, 0);
        t.setLayoutParams(params);
        TextView textView = makeText(name, params);
        t.addView(textView);

        Spinner spinner = createSpinner(elements, new AdapterView.OnItemSelectedListener() {
            int index = count;

            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                currentUnits[index] = i;
            }

            public void onNothingSelected(AdapterView<?> adapterView) {
            }
        });
        spinners[count] = spinner;
        spinner.setLayoutParams(params);

        params = new TableRow.LayoutParams(dipToPx(140),
                TableRow.LayoutParams.WRAP_CONTENT);
        params.setMargins(dipToPx(4)
                , 0, 0, 0);
        EditText editText = makeEditText(t, params);
        textBoxes[count] = editText;
        t.addView(spinner);
        return t;
    }

    private TextView makeText(CharSequence name, LinearLayout.LayoutParams params) {
        TextView textView = new TextView(this);
        textView.setText(name);
        textView.setTextColor(Color.BLACK);
        textView.setLayoutParams(params);
        textView.setTextSize(dipToPx(11));
        return textView;
    }

    private EditText makeEditText(TableRow t, TableRow.LayoutParams params) {
        EditText editText = new EditText(this);
        editText.setInputType(InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE | InputType.TYPE_CLASS_NUMBER |
                InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED);
        editText.setLayoutParams(params);
        t.addView(editText);
        return editText;
    }

    /**
     * Not sure if this works or not
     */
    private int dipToPx(int dip) {
        return (int) (TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics()) + .5);
    }

    public double[] initializeUnits(int conversion) {
        return convertToDouble(getResources().getStringArray(conversion));
    }

    public Spinner createSpinner(CharSequence[] elements, AdapterView.OnItemSelectedListener a) {
        Spinner s = new Spinner(this);
        CustomAdapter<CharSequence> spinnerArrayAdapter =
                new CustomAdapter<CharSequence>(this, android.R.layout.simple_spinner_item, elements);
        spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        s.setAdapter(spinnerArrayAdapter);
        s.setOnItemSelectedListener(a);
        return s;
    }

    public double[] convertToDouble(String[] values) {
        double[] result = new double[values.length];
        for (int i = 0; i < values.length; i++) {
            String current = values[i];
            result[i] = new Formula("", current, "").freeEvaluate();
        }
        return result;
    }

    /**
     * Save variables on screen rotation
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putIntArray("currentUnits", currentUnits);
        String[] text = new String[textBoxes.length];
        for (int i = 0; i < textBoxes.length; i++)
            text[i] = textBoxes[i].getEditableText().toString();
        outState.putStringArray("textBoxes", text);
    }

    public int showDialog(String variable, final Var a, final Var b) {
        hide();

        final CharSequence[] items = {Html.fromHtml(names[findName(variable)] + " = " + Rounding.round(a)),
                Html.fromHtml(names[findName(variable)] + " = " + Rounding.round(b))};
        AlertDialog.Builder builder = new AlertDialog.Builder(GenericSolver.this);
        builder.setTitle(getString(R.string.choose_value));
        final int[] option = {-1};
        builder.setItems(items, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int pos) {
                Var x;
                if (pos == 0) {
                    Global.values.put(a.name, a);
                    x = a; //TODO: put this back in evaluate method
                } else {
                    Global.values.put(b.name, b);
                    x = b;
                }
                int index = findName(x.name);
                textBoxes[index].setText(
                        Rounding.round(x.value / conversionFactors[index][currentUnits[index]], x.sigFig) + "");
                solve();

            }
        });
        builder.create().show();
        return option[0];
    }

    private void hide() {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        for (EditText text : textBoxes)
            imm.hideSoftInputFromWindow(text.getWindowToken(), 0);
    }


}